package com.lineage.server.model.drop;

import com.lineage.config.ConfigRate;
import com.lineage.server.datatables.DropItemEnchantTable;
import com.lineage.server.datatables.DropItemTable;
import com.lineage.server.datatables.DropLimitTable;
import com.lineage.server.datatables.ItemTable;
import com.lineage.server.datatables.MapsTable;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.model.Instance.L1NpcInstance;
import com.lineage.server.model.L1Inventory;
import com.lineage.server.templates.L1Drop;
import com.lineage.server.templates.L1DropEnchant;
import com.lineage.server.templates.L1DropMap;
import com.lineage.server.templates.L1DropMob;
import com.lineage.server.templates.L1Item;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SetDrop implements SetDropExecutor {
	private static final Log _log = LogFactory.getLog(SetDrop.class);

	private static final Random _random = new Random();

	private static Map<Integer, ArrayList<L1Drop>> _droplist;

	private static Map<Integer, ArrayList<L1DropMap>> _droplistX;

	private static Map<Integer, L1DropMob> _moblist;

	public void addDropMap(Map<Integer, ArrayList<L1Drop>> droplists) {
		if (_droplist != null)
			_droplist.clear();
		_droplist = droplists;
	}

	public void addDropMapX(Map<Integer, ArrayList<L1DropMap>> droplists) {
		if (_droplistX != null)
			_droplistX.clear();
		_droplistX = droplists;
	}

	public void addDropMob(Map<Integer, L1DropMob> droplists) {
		if (_moblist != null)
			_moblist.clear();
		_moblist = droplists;
	}

	public void setDrop(L1NpcInstance npc, L1Inventory inventory) {
		setDrop(npc, inventory, 0.0D);
	}

	public void setDrop(L1NpcInstance npc, L1Inventory inventory, double random) {
		int mobId = npc.getNpcTemplate().get_npcId();
		int mapid = npc.getMapId();
		ArrayList<L1DropMap> droplistX = _droplistX.get(Integer.valueOf(mapid));
		if (droplistX != null)
			setDrop(npc, inventory, droplistX);
		if (_moblist != null)
			setDrop(npc, inventory, _moblist);
		ArrayList<L1Drop> dropList = _droplist.get(Integer.valueOf(mobId));
		if (dropList == null)
			return;
		double droprate = ConfigRate.RATE_DROP_ITEMS;
		if (droprate <= 0.0D)
			droprate = 0.0D;
		droprate += random;
		double adenarate = ConfigRate.RATE_DROP_ADENA;
		if (adenarate <= 0.0D)
			adenarate = 0.0D;
		if (droprate <= 0.0D && adenarate <= 0.0D)
			return;
		Iterator<L1Drop> iterator = dropList.iterator();
		while (iterator.hasNext()) {
			L1Drop drop = iterator.next();
			int itemId = drop.getItemid();
			if (adenarate == 0.0D && itemId == 40308)
				continue;
			int randomChance = _random.nextInt(1000000) + 1;
			double rateOfMapId = MapsTable.get().getDropRate(npc.getMapId());
			double rateOfItem = DropItemTable.get().getDropRate(itemId);
			if (droprate == 0.0D)
				continue;
			if (drop.getChance() * droprate * rateOfMapId * rateOfItem < randomChance)
				continue;
			double amount = DropItemTable.get().getDropAmount(itemId);
			long min = (long) (drop.getMin() * amount);
			long max = (long) (drop.getMax() * amount);
			long itemCount = min;
			long addCount = max - min + 1L;
			if (addCount > 1L)
				itemCount += _random.nextInt((int) addCount);
			if (itemId == 40308)
				itemCount = (long) (itemCount * adenarate);
			if (itemCount < 0L)
				itemCount = 0L;
			if (itemCount > 2000000000L)
				itemCount = 2000000000L;
			if (itemCount > 0L) {
				if (!chexkItemAdd(inventory, itemId) || DropLimitTable.getInstance().giveCheck(itemId, (int) itemCount))
					continue;
				additem(npc, inventory, itemId, itemCount);
				continue;
			}else {
				_log.error("NPC加入背包物件数量为0(" + mobId + " itemId: " + itemId + ")");
			}
		}
	}

	private void setDrop(L1NpcInstance npc, L1Inventory inventory, Map<Integer, L1DropMob> moblist) {
		Iterator<Integer> iterator = moblist.keySet().iterator();
		while (iterator.hasNext()) {
			Integer key = iterator.next();
			int random = _random.nextInt(1000) + 1;
			int week = ((L1DropMob) moblist.get(key)).getweek();
			int starttime = ((L1DropMob) moblist.get(key)).getStarttime();
			int unitytime = ((L1DropMob) moblist.get(key)).getUnitytime();
			Calendar date = Calendar.getInstance();
			int nowWeek = date.get(7) - 1;
			int nowHour = date.get(11);
			if (nowWeek == 0)
				nowWeek += 7;
			if (((L1DropMob) moblist.get(key)).getChance() < random)
				continue;
			if (week > 0 && starttime < 0 && unitytime < 0) {
				if (week != nowWeek)
					continue;
			} else if (week > 0 && starttime >= 0 && unitytime >= 0) {
				if (week != nowWeek || nowHour < starttime)
					continue;
				if (nowHour >= unitytime)
					continue;
			} else if (week < 0 && starttime >= 0 && unitytime >= 0) {
				if (nowHour < starttime)
					continue;
				if (nowHour >= unitytime)
					continue;
			}
			int min = ((L1DropMob) moblist.get(key)).getMin();
			int max = ((L1DropMob) moblist.get(key)).getMax();
			int addCount = max - min + 1;
			if (addCount > 1)
				min += _random.nextInt(addCount);
			if (min > 0) {
				if (!chexkItemAdd(inventory, key.intValue())
						|| DropLimitTable.getInstance().giveCheck(key.intValue(), min)) {
					continue;
				}
				additem(inventory, key.intValue(), min);
				continue;
			}else {
				_log.error("NPC加入背包物件数量为0(" + npc.getNpcId() + " itemId: " + key + ") 掉落");
			}
		}
	}

	private void additem(L1Inventory inventory, int itemId, long itemCount) {
		additem(inventory, itemId, itemCount, 0, 0);
	}

	private void additem(L1Inventory inventory, int itemId, long itemCount, int enchant_min, int enchant_max) {
		try {
			L1Item tmp = ItemTable.get().getTemplate(itemId);
			if (tmp == null) {
				_log.error("掉落物品设置错误(无这编号物品): " + itemId);
				return;
			}
			if (tmp.isStackable()) {
				L1ItemInstance item = ItemTable.get().createItem(itemId);
				if (item != null) {
					item.setCount(itemCount);
					if (enchant_min > 0 && enchant_max > 0)
						if (enchant_min == enchant_max) {
							item.setEnchantLevel(enchant_min);
						} else {
							item.setEnchantLevel(_random.nextInt(enchant_max) + enchant_min);
						}
					inventory.storeItem(item);
				}
			} else {
				int i = 0;
				while (i < itemCount) {
					L1ItemInstance item2 = ItemTable.get().createItem(itemId);
					if (item2 != null) {
						item2.setCount(1L);
						if (enchant_min > 0 && enchant_max > 0)
							if (enchant_min == enchant_max) {
								item2.setEnchantLevel(enchant_min);
							} else {
								item2.setEnchantLevel(_random.nextInt(enchant_max) + enchant_min);
							}
						inventory.storeItem(item2);
					}
					i++;
				}
			}
		} catch (Exception e) {
			_log.error(e.getLocalizedMessage(), e);
		}
	}

	private void setDrop(L1NpcInstance npc, L1Inventory inventory, ArrayList<L1DropMap> dropListX) {
		double droprate = ConfigRate.RATE_DROP_ITEMS;
		if (droprate <= 0.0D)
			droprate = 0.0D;
		double adenarate = ConfigRate.RATE_DROP_ADENA;
		if (adenarate <= 0.0D)
			adenarate = 0.0D;
		if (droprate <= 0.0D && adenarate <= 0.0D)
			return;
		Iterator<L1DropMap> iterator = dropListX.iterator();
		while (iterator.hasNext()) {
			L1DropMap drop = iterator.next();
			int itemId = drop.getItemid();
			if (adenarate == 0.0D && itemId == 40308)
				continue;
			if (npc.getMapId() != drop.get_mapid())
				continue;
			int randomChance = _random.nextInt(1000000) + 1;
			double rateOfMapId = MapsTable.get().getDropRate(npc.getMapId());
			double rateOfItem = DropItemTable.get().getDropRate(itemId);
			boolean noadd = (drop.getChance() * droprate * rateOfMapId * rateOfItem < randomChance);
			if (droprate == 0.0D)
				continue;
			if (noadd)
				continue;
			double amount = DropItemTable.get().getDropAmount(itemId);
			long min = (long) (drop.getMin() * amount);
			long max = (long) (drop.getMax() * amount);
			long itemCount = min;
			long addCount = max - min + 1L;
			if (addCount > 1L)
				itemCount += _random.nextInt((int) addCount);
			if (itemId == 40308)
				itemCount = (long) (itemCount * adenarate);
			if (itemCount < 0L)
				itemCount = 0L;
			if (itemCount > 2000000000L)
				itemCount = 2000000000L;
			if (itemCount > 0L) {
				if (!chexkItemAdd(inventory, itemId) || DropLimitTable.getInstance().giveCheck(itemId, (int) itemCount)) {
					continue;
				}
				additem(npc, inventory, itemId, itemCount);
				continue;
			}else {
				_log.error("NPC加入背包物件数量为0(" + npc.getNpcId() + " itemId: " + itemId + ") 指定地图");
			}
		}
	}

	private void additem(L1NpcInstance npc, L1Inventory inventory, int itemId, long itemCount) {
		try {
			L1Item tmp = ItemTable.get().getTemplate(itemId);
			if (tmp == null) {
				_log.error("掉落物品设置错误(无这编号物品): " + itemId);
				return;
			}
			if (tmp.isStackable()) {
				L1ItemInstance item = ItemTable.get().createItem(itemId);
				if (item != null) {
					item.setCount(itemCount);
					ArrayList<L1DropEnchant> datalist = DropItemEnchantTable.get().getDatalist(npc.getNpcId());
					if (datalist != null) {
						Iterator<L1DropEnchant> iterator = datalist.iterator();
						while (iterator.hasNext()) {
							L1DropEnchant data = iterator.next();
							if (data.getItemid() == itemId) {
								int level = DropItemEnchantTable.get().getEnchant(data);
								item.setEnchantLevel(level);
								break;
							}
						}
					}
					inventory.storeItem(item);
				}
			} else {
				int i = 0;
				while (i < itemCount) {
					L1ItemInstance item2 = ItemTable.get().createItem(itemId);
					if (item2 != null) {
						item2.setCount(1L);
						ArrayList<L1DropEnchant> datalist2 = DropItemEnchantTable.get().getDatalist(npc.getNpcId());
						if (datalist2 != null) {
							Iterator<L1DropEnchant> iterator2 = datalist2.iterator();
							while (iterator2.hasNext()) {
								L1DropEnchant data2 = iterator2.next();
								if (data2.getItemid() == itemId) {
									int level2 = DropItemEnchantTable.get().getEnchant(data2);
									item2.setEnchantLevel(level2);
									break;
								}
							}
						}
						inventory.storeItem(item2);
					}
					i++;
				}
			}
		} catch (Exception e) {
			_log.error(e.getLocalizedMessage(), e);
		}
	}

	private boolean chexkItemAdd(L1Inventory inventory, int itemId) {
		List<Integer> npcBackpackItemIdlist = (List<Integer>) inventory.getItems().stream()
				.map(L1ItemInstance::getItemId).collect(Collectors.toList());
		if (npcBackpackItemIdlist.contains(Integer.valueOf(itemId)))
			return false;
		return true;
	}
}
